package copyengine.ui.dragdrop.impl.manger
{
	import copyengine.ui.dragdrop.IDragDropEngine;
	import copyengine.ui.dragdrop.IDragDropManger;
	import copyengine.ui.dragdrop.IDragDropReceiver;
	import copyengine.ui.dragdrop.IDragDropSource;
	import copyengine.ui.dragdrop.IDragDropTarget;
	import copyengine.utils.GeneralUtils;

	import flash.display.DisplayObjectContainer;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.MouseEvent;

	public class CEDragDropMangerCore implements IDragDropManger
	{
		protected var layer:DisplayObjectContainer;
		protected var engine:IDragDropEngine;

		protected var dragdropSourceIcon:DisplayObjectContainer

		protected var dragDropReceiverList:Vector.<IDragDropReceiver>;

		/**
		 * for now only use on attribute to recorder current target .
		 * that is assume at each point only contain one target. if at point have more target
		 * then change the receiver to vector.
		 */
		protected var currentReceiver:IDragDropReceiver;

		public function CEDragDropMangerCore()
		{
		}

		final public function setup(_layer:DisplayObjectContainer, _engine:IDragDropEngine):void
		{
			layer = _layer;
			layer.mouseChildren = false; // layer child can not respond mouse event

			engine = _engine;
			engine.manger = this;

			layer.visible = false;

			dragDropReceiverList = new Vector.<IDragDropReceiver>();
		}

		final public function startDragDrop(_source:IDragDropSource, _x:Number, _y:Number):void
		{
			var g:Graphics = (layer as Sprite).graphics;
			g.clear();
			g.beginFill(0, 0);
			g.drawRect(0, 0, layer.stage.stageWidth, layer.stage.stageHeight);
			g.endFill();
			layer.visible = true;

			addListener();

			//manger only put this icon on stage ,not respond for it move.
			dragdropSourceIcon = _source.createDragIcon();
			if (dragdropSourceIcon != null)
			{
				layer.addChild(dragdropSourceIcon);
			}

			for each (var receiver:IDragDropReceiver in dragDropReceiverList)
			{
				receiver.onDragDropStart();
			}

			doStartDragDrop(_source, _x, _y);
		}

		final public function onEndDragDrop():void
		{
			layer.visible = false;

			removeListener();

			GeneralUtils.removeTargetFromParent(dragdropSourceIcon);

			while (dragDropReceiverList.length > 0)
			{
				dragDropReceiverList.pop().onDragDropEnd();
			}

			dragdropSourceIcon = null;
		}

		final public function addDragDropTarget(_target:IDragDropTarget):void
		{
			engine.addDragDropTarget(_target);
		}

		final public function addDragDropReceiver(_receiver:IDragDropReceiver):void
		{
			dragDropReceiverList.push(_receiver);
		}

		//==============
		//== Protected
		//==============
		protected function doStartDragDrop(_source:IDragDropSource, _x:Number, _y:Number):void
		{
			engine.startDragDrop(_source, _x, _y);
		}

		protected function onMouseMove(e:MouseEvent):void
		{
			engine.move(e.stageX, e.stageY);
		}

		protected function onMouseDown(e:MouseEvent):void
		{
		}

		protected function onMouseUp(e:MouseEvent):void
		{
		}

		//=============
		//==Private
		//=============

		private function findReceiverAtPoint(_x:Number, _y:Number):IDragDropReceiver
		{
			for (var i:int = 0; i < dragDropReceiverList.length; i++)
			{
				if (dragDropReceiverList[i].isPositionInTarget(_x, _y))
				{
					return dragDropReceiverList[i];
				}
			}
			return null;
		}

		private function addListener():void
		{
			GeneralUtils.addTargetEventListener(layer, MouseEvent.MOUSE_MOVE, parentOnMouseMove);
			GeneralUtils.addTargetEventListener(layer, MouseEvent.MOUSE_DOWN, parentOnMouseDown);
			GeneralUtils.addTargetEventListener(layer, MouseEvent.MOUSE_UP, parentOnMouseUp);
		}

		private function removeListener():void
		{
			GeneralUtils.removeTargetEventListener(layer, MouseEvent.MOUSE_MOVE, parentOnMouseMove);
			GeneralUtils.removeTargetEventListener(layer, MouseEvent.MOUSE_DOWN, parentOnMouseDown);
			GeneralUtils.removeTargetEventListener(layer, MouseEvent.MOUSE_UP, parentOnMouseUp);
		}

		private function parentOnMouseDown(e:MouseEvent):void
		{
			stopEvent(e);
			if (currentReceiver != null)
			{
				currentReceiver.onMouseDown(e);
			}
			onMouseDown(e);
		}

		private function parentOnMouseUp(e:MouseEvent):void
		{
			stopEvent(e);
			if (currentReceiver != null)
			{
				currentReceiver.onMouseUp(e);
			}
			onMouseUp(e);
		}

		private function parentOnMouseMove(e:MouseEvent):void
		{
			stopEvent(e);

			var newReceiver:IDragDropReceiver = findReceiverAtPoint(e.stageX, e.stageY);
			if (currentReceiver != newReceiver)
			{
				if (currentReceiver != null)
				{
					currentReceiver.onMouseRollOut(e);
				}
				if (newReceiver != null)
				{
					newReceiver.onMouseRollOver(e);
				}
			}
			else
			{
				if (currentReceiver != null)
				{
					currentReceiver.onMouseMove(e);
				}
			}
			currentReceiver = newReceiver;

			onMouseMove(e);
		}


		private function stopEvent(e:MouseEvent):void
		{
			e.stopImmediatePropagation();
		}

	}
}
